not logged in | [Login]
Always use radiusd -X when debugging!
This first example assumes the server is only performing mac-auth. It checks MAC addresses against a users style file.
Most NASes usually send the MAC address in the Calling-Station-ID attribute. There are several common formats:
Again, depending on the NAS, these can be either upper-case or lower-case hex.
It is sensible to re-format these into a single format at the server. The
following policy is available in FreeRADIUS version 3 onwards, in
[[raddb/policy.d/canonicalization|https://github.com/FreeRADIUS/freeradius-server/blob/v3.0.x/raddb/policy.d/canonicalization.
#
# Rewrite called station id attribute into a standard format.
#
rewrite_calling_station_id {
        if (Calling-Station-Id =~ /([0-9a-f]{2})[-:]?([0-9a-f]{2})[-:.]?([0-9a-f]{2})[-:]?([0-9a-f]{2})[-:.]?([0-9a-f]{2})[-:]?([0-9a-f]{2})/i) {
                update request {
                        Calling-Station-Id := "%{tolower:%{1}-%{2}-%{3}-%{4}-%{5}-%{6}}"
                }
        }
        else {
                noop
        }
}
Create a new instance of the files module to read a new file of permitted MAC addresses.
files authorized_macs {
        # The default key attribute to use for matches.  The content
        # of this attribute is used to match the "name" of the
        # entry.
        key = "%{Calling-Station-ID}"
        usersfile = ${confdir}/authorized_macs
        #  If you want to use the old Cistron 'users' file
        #  with FreeRADIUS, you should change the next line
        #  to 'compat = cistron'.  You can the copy your 'users'
        #  file from Cistron.
        compat = no
}
This is the list of permitted MAC addresses, as read by the new files configuration above.
00-11-22-33-44-55
        Reply-Message = "Device with MAC Address %{Calling-Station-Id} authorized for network access"
Finally, call the canonicalisation policy and new files module from the authorize section:
authorize {
        preprocess
        # If cleaning up the Calling-Station-Id...
        rewrite_calling_station_id
        # Now check against the authorized_macs file
        authorized_macs
        if (!ok) {
                # No match was found, so reject
                reject
        }
        else {
                # The MAC address was found, so update Auth-Type
                # to accept this auth.
                update control {
                        Auth-Type := Accept
                }
        }
}
This example shows how to mix 802.1x and mac-auth. The example does the following:
The files raddb/policy.conf, raddb/mods-available/files and raddb/authorized_macs
are the same as the plain mac-auth examples above.
authorize {
        preprocess
        # If cleaning up the Calling-Station-Id...
        rewrite_calling_station_id
        # If this is NOT 802.1x, assume mac-auth. We check this by testing
        # for the presence of the EAP-Message attribute in the request.
        if (!EAP-Message) {
                # Now check against the authorized_macs file
                authorized_macs
                if (!ok) {
                        reject
                }
                else {
                        # accept
                        update control {
                                Auth-Type := Accept
                        }
                }
        }
        else {
                # Normal FreeRADIUS virtual server config goes here e.g.
                eap
        }
}
This example shows how to perform both 802.1x and mac-auth. The example does the following:
The files raddb/policy.conf, raddb/mods-available/files and raddb/authorized_macs
are the same as the plain mac-auth examples above.
authorize {
        preprocess
        # If cleaning up the Calling-Station-Id...
        rewrite_calling_station_id
        # always check against the authorized_macs file first
        authorized_macs
        if (!ok) {
        # Reject if the MAC address was not permitted.
                reject
        }
        # If this is NOT 802.1x, mac-auth
        if (!EAP-Message) {
                # MAC address has already been checked, so accept
                update control {
                        Auth-Type := Accept
                }
        }
        else {
                # Normal FreeRADIUS virtual server config goes here e.g.
                eap
        }
}
Although this configuration is more complex, you should probably use it if the server is going to process both web-auth and mac-auth requests, here is the rationale:
This configuration attempts to prevent this kind of spoofing:
Service-Type == 'Call-Check' AVP as an explicit indication that the NAS wants to do Mac-Auth. If your NAS sends this in Access-Request packets, you should remove the User-Name =~ /^%{Calling-Station-ID}$/i sub-condition from the authorize section.For this configuration to work, you must configure the password format for Mac-Auth to use the same octet separator as the Calling-Station-ID attribute.
As per example 1
As per example 1
As per example 1
authorize {
    #
    # (Optional) May help if your NAS doesn't let you specify separators for the User-Name value
    #
    #rewrite_calling_station_id
    #
    # The EAP module should be listed before the Mac-Auth section if concurrent 802.1X/MAC authentication
    # (Mac-Auth bypass etc...) is being used.
    #
    eap
    #
    # Machine (Calling-Station-ID based) authentication
    #
    # RFC 2865 says that a Service-Type value of Call Check is used
    # to specify this kind of authentication (though were now dealing with ethernet ports instead of lines).
    #
    if((Service-Type == 'Call-Check') || (User-Name =~ /^%{Calling-Station-ID}$/i)){
        update control {
                Auth-Type = 'CSID'
        }
    }
    #
    # If the CHAP module is called, it must be *after* the check for CSID authentication
    #
    # chap
}
authenticate {
    #
    # Authentication based on Calling-Station-ID
    #      
    # Calling-Station-ID authentication is usually done by comparing normalised
    # forms of the Calling-Station-ID and User-name fields.
    #
    Auth-Type CSID {
            #
            # Optionally a CHAP-Password attribute is included which is
            # md5(ChapID + Calling-Station-ID + Request Authenticator).
            #
            if(Chap-Password){
                    update control {
                        Cleartext-Password := "%{Calling-Station-ID}"
                    }
                    chap
            }
            else {
                ok  
            }  
    }
}
post-auth {
    if(control:Auth-Type == 'CSID'){
        # Authorization happens here
        authorized_macs.authorize
        if(!ok){
                reject
        }
    }
}
Follow any of the recipes above and then make the following modifications.
Note: The recipe below will work with any NAS that includes the SSID in the Called-Station-ID string with the format : e.g. 00-11-22-33-44-55:MY_SSID_1. There is no standard for this, and vendors may include the SSID in its own vendor specific attribute (VSA). If unsure, run the server in debug mode (-X) and check the contents of incoming requests.
If your vendor's NAS uses a VSA, omit the call to 'rewrite_called_station_id', do not add the additional attributes to the dictionary, and insert that VSA into the key attribute in place of '%{Called-Station-SSID}' e.g. key = "%{VENDOR_SSID_VSA}.%{Calling-Station-ID}".
Use next free attribute number between 3000-4000 and insert the following definition.
# The SSID the supplicant/user device connected to ATTRIBUTE Called-Station-SSID 3010 string
Add the following policy stanza to policy.conf.
#
# Rewrite called station id attribute into a standard format.
# If a 6th seperator is present, write the trailing chars into Called-Station-SSID
#
rewrite_called_station_id {
        if(Called-Station-Id =~ /^([0-9a-f]{2})[-:]?([0-9a-f]{2})[-:.]?([0-9a-f]{2})[-:]?([0-9a-f]{2})[-:.]?([0-9a-f]{2})[-:]?([0-9a-f]{2})[-:]?([-a-z0-9_. ]*)?/i){
                update request {
                        Called-Station-Id := "%{1}%{2}%{3}%{4}%{5}%{6}"
                        Called-Station-SSID := "%{7}"
                }
        }
        else {
                noop
        }
}
Add the a module call for 'rewrite_calling_station_id' to the authorize section directly above the call to 'rewrite_calling_station_id'.
authorize {
  ...
  # break called station ID into the BSSID and SSID
  rewrite_called_station_id
  # if cleaning up the Calling-Station-Id...
  rewrite_calling_station_id
  ...
}
modify the key attribute of the authorized_macs files instance
files authorized_macs {
        # The default key attribute to use for matches.  The content
        # of this attribute is used to match the "name" of the
        # entry.
        key = "%{Called-Station-SSID}.%{Calling-Station-ID}"
        usersfile = ${confdir}/authorized_macs
        #  If you want to use the old Cistron 'users' file
        #  with FreeRADIUS, you should change the next line
        #  to 'compat = cistron'.  You can the copy your 'users'
        #  file from Cistron.
        compat = no
}
Entries should now be in the following format.
MY_SSID_1.00-11-22-33-44-55
    Reply-Message = "Device with MAC Address %{Calling-Station-Id} authorized for network access on SSID %{Called-Station-SSID}"
As above.
As above.
Add the a module call for 'rewrite_calling_station_id' to the authorize section directly above the call to 'rewrite_calling_station_id'.
authorize {
    preprocess
    rewrite_calling_station_id
    rewrite_called_station_id
    if("%{sql:SELECT COUNT(*) FROM `SSIDMACAUTH` WHERE macaddress = '%{Calling-Station-ID}' AND SSID = '%{Called-Station-SSID}'}" >= 1){
          ok
        update control {
            Auth-Type := Accept
        }
    }
    else{
        reject
    }
}
    Last edited by Matthew Newton (mcnewton), 2016-04-17 21:00:55
Sponsored by Network RADIUS 